#include "main_header.h"
#include <sys/socket.h>
#define BLOCK_SIZE (4 * 1024 * 1024)      // 4MB接收块
#define MMAP_CHUNK (256 * 1024 * 1024)    // 256MB映射段
#define MAX_FILE_SIZE 1024
//0723night
int putbigfile(off_t existsize, off_t totalSize, int fd, int netfd) {
    // 调整文件大小
    ftruncate(fd, totalSize);
    
   
    char *pmap = mmap(NULL, totalSize, PROT_WRITE, MAP_SHARED, fd, 0);
    if (pmap == MAP_FAILED) {
        perror("mmap");
        return -1;  
    }
    
    char *p = pmap + existsize;
    off_t remain = totalSize - existsize;
    const int MAX_BLOCK_SIZE = 1048576; // 1MB
    
    while (remain > 0) {
        int blockSize = (remain > MAX_BLOCK_SIZE) ? MAX_BLOCK_SIZE : remain;
        int dataLen;
        
        // 接收块大小
        if (recvn(netfd, &dataLen, sizeof(int)) <= 0) {
            break;
        }
        
        // 接收数据块
        if (recvn(netfd, p, dataLen) <= 0) {
            break;
        }
        
        p += dataLen;
        remain -= dataLen;
    }
    
    munmap(pmap, totalSize);
    return 0;
}
// 处理puts函数
int user_puts(dirStack_t *dirStack,char* user,int netfd,MYSQL *db , char *server_dir,file_t *file)
{
    train_t train;
    printf("服务端执行puts命令\n");
    char username[1024]={0};
    strcat(username,user);
    //1.接收文件名
    recvn(netfd,&train.length,sizeof(train.length));
    recvn(netfd,train.data,train.length);
    char filename[1024]={0};
    strcat(filename,train.data);
    // 2、从客户端收md5码
    bzero(&train,sizeof(train));
    recvn(netfd,&train.length,sizeof(train.length));
    recvn(netfd,train.data,train.length);
    //printf("上传文件的md5码:%s\n",train.data);  
    char *md5=train.data;
    // 拼接服务器地址和md5值
    char md5_path[1024]={0};
    snprintf(md5_path,sizeof(md5_path),"%s/%s",server_dir,md5);
    // 3、得到当前的路径
    int primary_key=dirStack->idArr[dirStack->size - 1];
    char sql[1024]={0};
    snprintf(sql,sizeof(sql),"select path from file where id=%d",primary_key);
    const char *sql_select=sql;
    int count=selectFile1(sql_select,db,file);
    //
    char *current_path=file->file[0].path;
    //printf("current_path:%s\n",current_path);
    // bzero(file->file[0].path,sizeof(file->file[0].path));

    // 拼接出文件的path
    char path[257] = {0};
    strcat(path, current_path);
    strcat(path, filename);
    //snprintf(path, sizeof(path), "%s%s", current_path, filename);
    //printf("path = <%s>\n", path);
    bzero(file->file[0].path, sizeof(file->file[0].path));

    //4.根据md5在数据库中查找文件
    char sql_md5[1024]={0};
    snprintf(sql_md5,sizeof(sql_md5),"select id from file where md5='%s'",md5);
    const char *sel_md5=sql_md5;
    int count_md5=selectFile1(sel_md5,db,file);
    if(count_md5!=0){
        //查到了，触发秒传，插入文件的信息
        printf("秒传\n");
        char sql_insert_file[1024]={0};
        snprintf(sql_insert_file, sizeof(sql_insert_file),"insert into file(username,filename,path,md5,parent_id,md5_path,type) values ('%s','%s','%s','%s','%d','%s','%c')",username,filename,path,md5,primary_key,md5_path,'f');
        const char *sql_insert=sql_insert_file;
        int ret_insert=execDB(sql_insert,db);
        ERROR_CHECK(ret_insert,-1,"秒传时插入数据库失败");
        printf("秒传时插入数据库成功\n");
        //给客户端发送秒传标志
        //char bufs[1024]={"秒传"};
    int tmp=1;
        send(netfd,&tmp,sizeof(int),0);
        return 0;
    }
    else{ int tmp2=0;
    //没有进行秒传
    send(netfd,&tmp2,sizeof(int),0);
    }
    //5.进行正常的上传逻辑
    int fd=open(filename,O_RDWR|O_CREAT,0666);
    if(fd==-1){
        printf("打开文件失败\n");
        return -1;
    }
    off_t existsize=lseek(fd,0,SEEK_END);
    send(netfd,&existsize,sizeof(off_t),MSG_NOSIGNAL);
    // 接收文件的大小
    off_t fileSize=0;
    int ret_filesize=recvn(netfd,&fileSize,sizeof(off_t));
    ERROR_CHECK(ret_filesize, 0, "recv file size failed");
    //设置大文件小文件标志位
    //0723night
    bool flag=(fileSize>MAX_FILE_SIZE)?true:false;
       if (fileSize > MAX_FILE_SIZE) {
        putbigfile(existsize, fileSize, fd, netfd);
    } else {
    
    // 接收文件内容
    while(1){
        bzero(train.data,sizeof(train.data));
        //printf("服务端执行puts命令\n");
        int dataLen = 0;
        if(recvn(netfd, &dataLen, sizeof(int)) <= 0) break;
        if(dataLen == 0) break;
        if(recvn(netfd, train.data,dataLen) <= 0) break;
        write(fd, train.data, dataLen);
             }
    }
    // 6、插入数据库表中
    char sql_insert_file[1024]={0};
  snprintf(sql_insert_file, sizeof(sql_insert_file),"insert into file(username,filename,path,md5,parent_id,md5_path,type) values ('%s','%s','%s','%s','%d','%s','%c')",username,filename,path,md5,primary_key,md5_path,'f');
   const char *sql_insert=sql_insert_file;
    int ret_insert=execDB(sql_insert,db);
    ERROR_CHECK(ret_insert,-1,"上传时插入数据库失败");
    printf("上传时插入数据库成功\n");
    close(fd);
    return 0;
}


